package cn.com.focu.im.sdk.service.disk;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import net.sf.json.JSONObject;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.lang.StringUtils;

import cn.com.focu.commons.util.HttpClientCallback;
import cn.com.focu.commons.util.encrypt.Base64;
import cn.com.focu.im.sdk.service.ServiceOperator;
import cn.com.focu.im.sdk.service.annotation.Operator;
import cn.com.focu.im.sdk.service.disk.entity.DeleteDirectory;
import cn.com.focu.im.sdk.service.disk.entity.NDiskEntity;
import cn.com.focu.im.sdk.service.disk.entity.NewDirectory;
import cn.com.focu.im.sdk.service.disk.entity.RenameDirectory;
import cn.com.focu.im.sdk.service.disk.exception.NDiskException;
import cn.com.focu.im.sdk.service.exception.ServiceException;
import cn.com.focu.im.sdk.service.group.exception.GroupNavbarException;
import cn.com.focu.im.sdk.util.CustomFilePart;

@Operator("ndisk")
public class NDiskOperator extends ServiceOperator {

	public NDiskOperator() {
	}

	public static class NDiskOperatorHolder {
		static NDiskOperator go = new NDiskOperator();
	}

	public static NDiskOperator getInstence() {
		return NDiskOperatorHolder.go;
	}

	/**
	 * 根据关键字获取群
	 * 
	 * @param pageSize
	 * @param current
	 * @param keyWord
	 * @return
	 */
	public String files(NDiskEntity get) throws NDiskException {
		String str = "";
		try {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("jsonString", URLEncoder.encode(JSONObject.fromObject(
					get).toString(), "UTF-8"));
			str = postReturnString(params);
			if (log.isDebugEnabled()) {
				log.debug(str);
			}
		} catch (IOException e) {
			throw new ServiceException(CANNOT_CONNECT_TO_SERVER);
		} catch (Exception e) {
			throw new NDiskException(e.getMessage(), e);
		}
		return str;
	}

	public File download(Long fileId) throws NDiskException {
		try {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("fileId", URLEncoder.encode(fileId.toString(), "UTF-8"));
			params.put("base64Encode", true + "");
			return (File) postReturnStream(params, new HttpClientCallback() {
				@Override
				public Object call(HttpMethod method) throws IOException {
					InputStream in = method.getResponseBodyAsStream();
					Header header = method
							.getResponseHeader("Content-Disposition");
					String disposition = header.getValue();
					String fileName = null;
					if (StringUtils.isNotBlank(disposition)
							&& disposition.indexOf("filename=") != -1) {
						fileName = disposition.substring(disposition
								.indexOf("filename=\"")
								+ ("filename=\"".length()), disposition
								.length() - 1);
						fileName = new String(Base64.decodeBuffer(URLDecoder
								.decode(fileName, "UTF-8")), "UTF-8");
					} else {
						fileName = UUID.randomUUID().toString();
					}

					String absolutePath = null;

					try {
						absolutePath = NDiskOperator.class.getResource("/")
								.getPath();
					} catch (Exception e) {
						absolutePath = NDiskOperator.class.getResource(".")
								.getPath();
					}

					absolutePath = absolutePath + File.separatorChar + "temp"
							+ File.separatorChar + fileName;

					saveFile(absolutePath, false, in);
					System.out.println("File saved:" + absolutePath);
					return new File(absolutePath);
				}
			});
		} catch (IOException e) {
			throw new ServiceException(CANNOT_CONNECT_TO_SERVER);
		} catch (Exception e) {
			throw new NDiskException(e.getMessage(), e);
		}
	}

	public boolean upload(NDiskEntity param, File[] files)
			throws NDiskException {
		List<Part> parts = new ArrayList<Part>();
		if (files != null && files.length > 0) {
			for (int i = 0; i < files.length; i++) {
				try {
					parts.add(new CustomFilePart("uploads", files[i]));
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
			}
			parts.add(new StringPart("jsonString", JSONObject.fromObject(param)
					.toString()));
		}
		try {
			Part[] partsArray = new Part[parts.size()];
			partsArray = parts.toArray(partsArray);
			String res = postFilesToServer(partsArray);
			JSONObject r = JSONObject.fromObject(res);
			if (r.has("success") && r.getBoolean("success"))
				return true;
			else
				return false;
		} catch (ConnectException e) {
			throw new ServiceException(CANNOT_CONNECT_TO_SERVER);
		} catch (IOException e) {
			throw new NDiskException(e.getMessage(), e);
		}
	}

	// public String downloadUrl(NDiskGet get) throws NDiskException {
	// try {
	// Map<String, String> params = new HashMap<String, String>();
	// params.put("jsonString", URLEncoder.encode(JSONObject.fromObject(
	// get).toString(), "UTF-8"));
	// return postReturnString(params);
	// } catch (IOException e) {
	// throw new ServiceException(CANNOT_CONNECT_TO_SERVER);
	// } catch (Exception e) {
	// throw new NDiskException(e.getMessage(), e);
	// }
	// }

	private static long saveFile(String absolutePath, boolean append,
			InputStream in) throws IOException {

		byte[] buffer = new byte[4096];

		File ftemp = new File(absolutePath);

		if (!ftemp.getParentFile().exists())
			ftemp.getParentFile().mkdirs();

		File f = new File(absolutePath);
		int len = 0;
		long totalSize = 0L;
		// 追加
		DataOutputStream o = new DataOutputStream(new FileOutputStream(f,
				append));
		try {
			while ((len = in.read(buffer)) != -1) {
				o.write(buffer, 0, len);
				o.flush();
			}
			totalSize = o.size();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			o.close();
			in.close();
		}
		return totalSize;
	}
	
	public Integer newDirectory(NewDirectory newDirectory){
		try {
			JSONObject json = JSONObject.fromObject(newDirectory);
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("jsonString", URLEncoder
					.encode(json.toString(), "UTF-8"));
			String re = postReturnString(params);
			if (log.isDebugEnabled()) {
				log.debug(re);
			}
			Integer resutlInteger = Integer.valueOf(re);
			if (resutlInteger > 0) {
				return resutlInteger;
			}
			switch (resutlInteger) {
			case 0:
				throw new NDiskException(resutlInteger,
						"数据提交失败，原因可能有：\n\t");
			case -1:
				throw new NDiskException(resutlInteger, "提交数据格式错误");
			default:
				throw new NDiskException(resutlInteger, OTHER_ERROR);
			}
		} catch (NumberFormatException e) {
			throw new GroupNavbarException("返回数值预期格式异常", e);
		} catch (IOException e) {
			throw new ServiceException(CANNOT_CONNECT_TO_SERVER);
		} catch (Exception e) {
			throw new GroupNavbarException(e.getMessage(), e);
		}
	}
	
	public Integer renameDirectory(RenameDirectory renameDirectory){
		try {
			JSONObject json = JSONObject.fromObject(renameDirectory);
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("jsonString", URLEncoder
					.encode(json.toString(), "UTF-8"));
			String re = postReturnString(params);
			if (log.isDebugEnabled()) {
				log.debug(re);
			}
			Integer resutlInteger = Integer.valueOf(re);
			if (resutlInteger > 0) {
				return resutlInteger;
			}
			switch (resutlInteger) {
			case 0:
				throw new NDiskException(resutlInteger,
						"数据提交失败，原因可能有：\n\t");
			case -1:
				throw new NDiskException(resutlInteger, "提交数据格式错误");
			default:
				throw new NDiskException(resutlInteger, OTHER_ERROR);
			}
		} catch (NumberFormatException e) {
			throw new GroupNavbarException("返回数值预期格式异常", e);
		} catch (IOException e) {
			throw new ServiceException(CANNOT_CONNECT_TO_SERVER);
		} catch (Exception e) {
			throw new GroupNavbarException(e.getMessage(), e);
		}
	}
	
	
	public Integer deleteDirectory(DeleteDirectory deleteDirectory){
		try {
			JSONObject json = JSONObject.fromObject(deleteDirectory);
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("jsonString", URLEncoder
					.encode(json.toString(), "UTF-8"));
			String re = postReturnString(params);
			if (log.isDebugEnabled()) {
				log.debug(re);
			}
			Integer resutlInteger = Integer.valueOf(re);
			if (resutlInteger > 0) {
				return resutlInteger;
			}
			switch (resutlInteger) {
			case 0:
				throw new NDiskException(resutlInteger,
						"数据提交失败，原因可能有：\n\t");
			case -1:
				throw new NDiskException(resutlInteger, "提交数据格式错误");
			default:
				throw new NDiskException(resutlInteger, OTHER_ERROR);
			}
		} catch (NumberFormatException e) {
			throw new NDiskException("返回数值预期格式异常", e);
		} catch (IOException e) {
			throw new ServiceException(CANNOT_CONNECT_TO_SERVER);
		} catch (Exception e) {
			throw new NDiskException(e.getMessage(), e);
		}
	}
	
}
